// src/trace.cpp
#include <chrono>
#include <cstdint>
#include <unordered_map>
#include <mutex>
#include <thread>
#include <unistd.h>
#include <dlfcn.h>
#include <cxxabi.h>
#include <fstream>
#include <iostream>
#include <execinfo.h>

#define NO_INSTRUMENT __attribute__((no_instrument_function))

// ---------------- 全局状态 ----------------
static std::mutex g_mutex;
static std::unordered_map<void*, std::chrono::high_resolution_clock::time_point> g_start_times;
static std::ofstream g_trace_file;
static bool g_first_event = true;

// ---------------- 时间戳 ----------------
NO_INSTRUMENT static uint64_t timestamp_us() {
    auto now = std::chrono::high_resolution_clock::now();
    return std::chrono::duration_cast<std::chrono::microseconds>(
               now.time_since_epoch())
        .count();
}

// ---------------- 使用 backtrace_symbols 获取函数名 ----------------
NO_INSTRUMENT static std::string get_func_name_from_backtrace(void* addr) {
    const int size = 1;
    void* buffer[size];
    buffer[0] = addr;
    char** strings = backtrace_symbols(buffer, size);
    std::string name = "unknown";

    if (strings) {
        std::string s(strings[0]);
        free(strings);

        // 尝试 demangle
        size_t begin = s.find('(');
        size_t plus = s.find('+', begin);
        if (begin != std::string::npos && plus != std::string::npos) {
            std::string mangled = s.substr(begin + 1, plus - begin - 1);
            int status = 0;
            char* dem = abi::__cxa_demangle(mangled.c_str(), nullptr, nullptr, &status);
            if (status == 0 && dem) {
                name = dem;
                free(dem);
            } else {
                name = mangled;
            }
        } else {
            name = s;
        }
    }
    return name;
}

// ---------------- 地址转函数名 ----------------
NO_INSTRUMENT static std::string demangle_func_name(void* addr) {
    Dl_info info;
    if (dladdr(addr, &info) && info.dli_sname) {
        int status = 0;
        char* dem = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
        std::string name = (status == 0 && dem) ? dem : info.dli_sname;
        free(dem);
        return name;
    }
    // fallback
    return get_func_name_from_backtrace(addr);
}

// ---------------- 初始化/析构 ----------------
struct NO_INSTRUMENT TraceInitializer {
    TraceInitializer() {
        g_trace_file.open("trace.json");
        g_trace_file << "{\n  \"traceEvents\": [\n";
        std::cerr << "[Trace] Recording to trace.json\n";
    }
    ~TraceInitializer() {
        g_trace_file << "\n  ]\n}\n";
        g_trace_file.close();
        std::cerr << "[Trace] trace.json written. Open chrome://tracing\n";
    }
};

static TraceInitializer g_trace_init;

// ---------------- 钩子函数 ----------------
extern "C" NO_INSTRUMENT void __cyg_profile_func_enter(void* this_fn, void* call_site) {
    uint64_t ts = timestamp_us();
    pid_t pid = getpid();
    auto tid = std::hash<std::thread::id>{}(std::this_thread::get_id());
    std::string name = demangle_func_name(this_fn);

    std::lock_guard<std::mutex> lock(g_mutex);
    g_start_times[this_fn] = std::chrono::high_resolution_clock::now();

    if (!g_first_event) g_trace_file << ",\n";
    g_first_event = false;

    g_trace_file << "    {\"name\":\"" << name
                 << "\",\"ph\":\"B\",\"pid\":" << pid
                 << ",\"tid\":" << tid
                 << ",\"ts\":" << ts << "}";
}

extern "C" NO_INSTRUMENT void __cyg_profile_func_exit(void* this_fn, void* call_site) {
    uint64_t ts = timestamp_us();
    pid_t pid = getpid();
    auto tid = std::hash<std::thread::id>{}(std::this_thread::get_id());
    std::string name = demangle_func_name(this_fn);

    std::lock_guard<std::mutex> lock(g_mutex);

    g_trace_file << ",\n    {\"name\":\"" << name
                 << "\",\"ph\":\"E\",\"pid\":" << pid
                 << ",\"tid\":" << tid
                 << ",\"ts\":" << ts << "}";
}